import type { LoginInfo } from '/#/store';
import type { ErrorMessageMode } from '/#/axios';
import { defineStore } from 'pinia';
import { store } from '/@/store';
import { RoleEnum } from '/@/enums/roleEnum';
import { PageEnum } from '/@/enums/pageEnum';
import { thirdAuthLogin } from '/@/api/auth'
import { 
  ROLES_KEY, LAST_ROUTE_PATH, USER_INFO_KEY,
  DB_DICT_DATA_KEY, TENANT_CONFIG_KEY
} from '/@/enums/cacheEnum';
import * as authCache from '/@/utils/cache/module';
import { getCache, setCache, setCacheByDynKey, getCacheByDynKey } from '/@/utils/cache/index';
import { GetUserInfoModel, UserInfo, LoginParams, ThirdLoginParams } from '/@/api/sys/model/userModel';
import { AuthInfo, TenantConfig } from '/@/model';
import { doLogout, getUserInfo, loginApi,phoneLoginApi,thirdLogin } from '/@/api/sys/user';
import { useI18n } from '/@/hooks/web/useI18n';
import { useMessage } from '/@/hooks/web/useMessage';
import { router } from '/@/router';
import { usePermissionStore } from '/@/store/modules/permission';
import { RouteRecordRaw } from 'vue-router';
import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
import { isArray } from '/@/utils';
import { getTenantId, setLastTenantId } from '/@/utils/tenant';
import { useGlobSetting } from '/@/hooks/setting';
import {useSso} from '/@/hooks/web/useSso';
import {queryAllDictItems} from '/@/api/infra/dict';
import { switchTenant } from '/@/api/sys/user';
import mitt, { Emitter } from '/@/utils/mitt';
import { initAppConfig } from '/@/utils/cache/module'

const glob = useGlobSetting();
const { t } = useI18n();
const { createMessage, notification } = useMessage();

// import { useRedo } from '/@/hooks/web/usePage';
// const redo = useRedo();
interface UserState {
  userInfo?: UserInfo;
  selectTenant?: TenantConfig;
  authInfo?: AuthInfo;
  token?: string;
  roleList: RoleEnum[];
  dictItems?: [];
  sessionTimeout?: boolean;
  lastUpdateTime: number;
  multiDept?: string | number;
  deptList?:[];
  tenantList?: [];
  isLogin: boolean
  emitter: Emitter;
}

/**
 * 获取数据的时候, 一定要先从store中获取, 获取不到再从浏览器本地缓存获取, 或者直接获取store即可, 
 * 不可只获取浏览器本地缓存中数据
 * 
 * 这样可以避免一个浏览器打开多个租户时数据错乱问题, 比如你打开两个tab, 新打开的tab肯定会加载整个应用
 * , 那么浏览器本地中的缓存数据就是最后刷新的tab数据, 如果先从store获取, 切换到另一个标签且没有刷新tab所在页面
 * 时候, 如果直接获取浏览器本地缓存数据, 会出现获取到的数据错乱问题
 */
export const useUserStore = defineStore({
  id: 'app-user',
  state: (): UserState => ({
    // 用户信息
    userInfo: undefined,
    authInfo: undefined,
    selectTenant: undefined,
    // 角色列表
    roleList: [],
    // 字典
    dictItems: [],
    // session过期时间
    sessionTimeout: false,
    // Last fetch time
    lastUpdateTime: 0,
    isLogin: false,
    // 全局事件 think gem
    emitter: mitt(),

  }),
  getters: {
    getUserInfo(): UserInfo {
      return this.userInfo || authCache.getUserInfo() || {};
    },
    getAuthInfo(): AuthInfo {
      return this.authInfo || authCache.getAuthInfo() || {};
    },
    getSelectTenant(): TenantConfig {
      const tenantInfo = this.selectTenant || authCache.getSelectTenant() || {};
      return tenantInfo
    },

    getIsSysAdminTenant(): boolean {
      const tenant = getCacheByDynKey<TenantConfig>(TENANT_CONFIG_KEY) || {};
      return tenant.id ===  useGlobSetting().platformTenantId
    },

    getToken(): string | undefined {
      const tenantInfo = this.selectTenant || authCache.getSelectTenant();
      const authInfo = this.authInfo || authCache.getAuthInfo()
      return tenantInfo ? authInfo?.accessToken || authCache.getCacheToken() : undefined;
    },
    getAllDictItems(): []{
      return this.dictItems || getCache(DB_DICT_DATA_KEY);
    },
    getRoleList(): RoleEnum[] {
      return this.roleList.length > 0 ? this.roleList : getCache<RoleEnum[]>(ROLES_KEY);
    },
    getSessionTimeout(): boolean {
      return !!this.sessionTimeout;
    },
    getLastUpdateTime(): number {
      return this.lastUpdateTime;
    },
    getLoginId() : string {
      return this.authInfo?.loginId || '';
    },
    getIsLogin() : boolean {
      return !!this.isLogin;
    },
    getEmitter(): any {
      return this.emitter;
    },
  },
  actions: {
    setToken(info: string | undefined) {
      this.authInfo = this.authInfo || {}
      this.authInfo.accessToken = info
      authCache.setAuthInfo({
        accessToken: info
      });
    },
    setAuthInfo(info: AuthInfo | undefined) {
      this.authInfo = { ...this.authInfo, ...(info || {}) }; 
      authCache.setAuthInfo(this.authInfo);
    },

    /**
     * 设置选择的租户
     */
    async setSelectTenant(tenantInfo: any) {
      const tenantId = tenantInfo?.id

      this.selectTenant = tenantInfo
      if (tenantId) {
        setLastTenantId(tenantId)
      }

      authCache.setSelectTenant(tenantInfo)
    },

    // 切换租户
    async switchTenant(tenantId: string, isLogin = false) {
      // if (!isLogin) {
 
      // } 
      const resp = await switchTenant({tenantId})
      await this.setSelectTenant({  ...resp })
    },

    // 前一个工作空间最后一次的路由
    setLastRoutePath(info: string | undefined) {
      setCacheByDynKey(LAST_ROUTE_PATH + this.userInfo?.currentTenantId + this.userInfo?.currentAppId, info);
    },
    setRoleList(roleList: RoleEnum[]) {
      this.roleList = roleList;
      authCache.setRole(roleList);
    },
    setUserInfo(info: UserInfo | undefined) {
      this.userInfo = info;
      this.lastUpdateTime = new Date().getTime();
      authCache.setUserInfo(info);
    }, 
    setAllDictItems(dictItems) {
      this.dictItems = dictItems;
      authCache.setDictItems(dictItems);
    },
    setSessionTimeout(flag: boolean) {
      this.sessionTimeout = flag;
    },
    resetState() {
      this.userInfo = undefined;
      this.dictItems = [];
      this.token = '';
      this.roleList = [];
      this.sessionTimeout = false;
      const tenantId = getTenantId()
      // setCacheByDynKey(TENANT_CONFIG_KEY + tenantId, undefined)
    },

    /**
     * 登录事件
     */
    async login(
      params: LoginParams & {
        goHome?: boolean;
        mode?: ErrorMessageMode;
      },
    ): Promise<AuthInfo | null> {
      try {
        const { goHome = true, mode, ...loginParams } = params;
        const authLoginData = await loginApi(loginParams, mode);
        // 这里先设置成false, 避免用户没有选择租户就刷新页面出现问题
        this.isLogin = false
        this.setAuthInfo(authLoginData)

        const userInfoResp : any = await getUserInfo()
        this.setUserInfo(userInfoResp.userInfo)
        // return this.afterLoginAction(goHome, authLoginData);
        return authLoginData
      } catch (error) {
        return Promise.reject(error);
      }
    }, 

    async thirdLogin(authLoginData): Promise<AuthInfo | null> {
      try {
        // 这里先设置成false, 避免用户没有选择租户就刷新页面出现问题
        this.isLogin = false
        this.setAuthInfo(authLoginData)

        const userInfoResp : any = await getUserInfo()
        this.setUserInfo(userInfoResp.userInfo)
        return authLoginData
      } catch (error) {
        return Promise.reject(error);
      }
    }, 

    /**
     * 登录完成处理
     * @param goHome
     */
    async afterLoginAction(goHome?: boolean, authLoginData?: any ) : Promise<any | null> {
      console.log('============== authLoginData', authLoginData);
      
      console.time("load_menu_time")
      if (!this.getToken) {
        console.warn('token is null');
        return null;
      }

      if (!authLoginData.tenantId) {
        console.warn('tenantId is null');
        return null
      }
      //获取用户信息
      const useProfile = await this.getUserInfoAction();
      const sessionTimeout = this.sessionTimeout;
      if (sessionTimeout) {
        this.setSessionTimeout(false);
      } else {
        const permissionStore = usePermissionStore();
        if (!permissionStore.isDynamicAddedRoute) {
          const routes = await permissionStore.buildRoutesAction();
          
          routes.forEach((route) => {
            router.addRoute(route as unknown as RouteRecordRaw);
          });
          router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
          permissionStore.setDynamicAddedRoute(true);
        }
        this.isLogin = true
        
        // @ts-ignore
        authCache.setUserInfo(useProfile?.userInfo)
        authCache.setAuthInfo({ isLogin: true })
        console.timeEnd('load_menu_time');
        
        const queryParams = router.currentRoute.value.query
        const redirect = queryParams?.redirect as string || queryParams?.backUrl as string
        const pagePath = (redirect || (useProfile && useProfile.userInfo?.homePath) || PageEnum.BASE_HOME)
        console.log('pagePath', pagePath);
        
        goHome && (await router.replace({
          path: (pagePath === '/' || pagePath === '') ? PageEnum.BASE_HOME : pagePath,
          query: { 
            tenantId: authLoginData.tenantId,
            // TODO appId先写死
            appId: '1'
          }
        }));
      }
      return authLoginData;
    },

    /**
     * 手机号登录
     * @param params
     */
    async phoneLogin(
      params: LoginParams & {
        goHome?: boolean;
        mode?: ErrorMessageMode;
      },
    ): Promise<GetUserInfoModel | null> {
      try {
        const { goHome = true, mode, ...loginParams } = params;
        const data = await phoneLoginApi(loginParams, mode);
        const { token } = data;
        // save token
        this.setToken(token);
        return this.afterLoginAction(goHome,data);
      } catch (error) {
        return Promise.reject(error);
      } 
    },
    /**
     * 获取用户信息
     */
    async getUserInfoAction(): Promise<GetUserInfoModel | null> {
      if (!this.getToken) {
        return null;
      }
      let data = await getUserInfo() as GetUserInfoModel;
      const {roles, userInfo} = data;
      // this.setSelectTenant(tenant)
      if(roles) {
        if (isArray(roles)) {
          const roleList = roles.map((item) => item.value) as RoleEnum[];
          this.setRoleList(roleList);
        } else {
          this.setRoleList([]);
        }
      }
      this.setUserInfo(userInfo as UserInfo);
      const sysAllDictItems = await queryAllDictItems();
      // 添加字典信息到缓存
      if(sysAllDictItems && sysAllDictItems.data) {
        this.setAllDictItems(sysAllDictItems.data);
      }
      console.log("userInfo: ", userInfo);
      return data;
    },

    /**
     * 退出登录
     */
    async logout(goLogin = false) {
      console.log('logout');
      
      if (this.getToken) {
        try {
          await doLogout();
          await initAppConfig()
        } catch {
          console.error('注销Token失败');
        }
      }
      this.setToken(undefined);
      this.setSelectTenant(null)
      this.setSessionTimeout(false);
      this.setUserInfo(undefined);
      this.resetState()
      

      //如果开启单点登录,则跳转到单点统一登录中心
      const openSso = useGlobSetting().openSso;
      if(openSso=='true'){
        await useSso().ssoLoginOut();
      }

      const currentRoute = router.currentRoute.value;
      let redirect : string = PageEnum.BASE_HOME;
      if (currentRoute.path !== '/' && currentRoute.path !== PageEnum.BASE_LOGIN) {
        redirect = decodeURIComponent(currentRoute.fullPath)
      }

      if (goLogin) {
        router.push({
          path: PageEnum.BASE_LOGIN,
          query: { redirect },
          replace: true
        })
      }
    },
  /**
   * 登录事件
   */
   async ThirdLogin(
        params: ThirdLoginParams & {
        goHome?: boolean;
        mode?: ErrorMessageMode;
       },
      ): Promise<any | null> {
      try {
          const { goHome = true, ...ThirdLoginParams } = params;
          const data = await thirdAuthLogin(ThirdLoginParams);
          const { authToken } = data;
          // save token
          this.setToken(authToken?.accessToken);
          // return this.afterLoginAction(goHome, data);
          return data
      } catch (error) {
          return Promise.reject(error);
      }
   },
    /**
     * 退出询问
     */
    confirmLoginOut() {
      const { createConfirm } = useMessage();
      const { t } = useI18n();
      createConfirm({
        iconType: 'warning',
        title: t('sys.app.logoutTip'),
        content: t('sys.app.logoutMessage'),
        onOk: async () => {
          await this.logout(true);
        },
      });
    },
  },
});

// Global emit by think gem
export function useEmitter() {
  return useUserStore().emitter;
}

// Need to be used outside the setup
export function useUserStoreWithOut() {
  return useUserStore(store);
}
